package com.one.service.impl;

import com.one.bean.User;
import com.one.mapper.UserMapper;
import com.one.service.SignService;
import com.one.utils.JedisUtil;
import com.one.utils.SignUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Create on 2022-01-14
 * <p>
 * Author: LiangWei
 * <p>
 * Description:
 **/
@Service
public class SignServiceImpl implements SignService {
    @Autowired(required = false)
    private JedisUtil jedisUtil;

    @Autowired
    private SignUtils signUtils;

    @Autowired
    private UserMapper userMapper;

    @Override
    public boolean doSign(Integer userId,LocalDate date) {
        Jedis jedis = jedisUtil.getJedis();
        //获取根据用户ID和日期获取用户的签到key
        //把signKey里面的dayOfMonth（本月第几天）偏移量设置为1（true）
        boolean flag = jedis.setbit(signUtils.getUserSignKey(userId,date),date.getDayOfMonth()-1,true);
        int signCount = 0;
        String type = String.format("u%d",date.getDayOfMonth());
        //取出最大长度为date.getDayOfMonth的二进制数
        List<Long> list = jedis.bitfield(signUtils.getUserSignKey(userId,date),"GET",type,"0");
        if(list!=null && list.size()>0){
            long v = list.get(0) == null?0:list.get(0);
            for(int i=0;i<date.getDayOfMonth();i++){
                if (v >> 1 << 1 == v) {
                    // 低位为0且非当天说明连续签到中断了
                    if (i > 0) break;
                } else {
                    signCount += 1;
                }
                v >>= 1;
            }
        }
        if(!flag){
            int moDou = 0;
            for(int i = 3;i<=date.lengthOfMonth();i+=3){
                if(i==signCount){
                    moDou+=50;
                    break;
                }
            }
            moDou+=10;
            //操作数据库增加蘑豆
            User user = new User();
            user.setId(userId);
            User userSelected = userMapper.selectById(userId);
            if(userSelected!=null){
                user.setMagicBean(userSelected.getMagicBean()+moDou);
                userMapper.update(user,null);
            }
        }
        jedisUtil.close(jedis);
        return !flag;
    }

    @Override
    public boolean checkSign(Integer userId,LocalDate date) {
        Jedis jedis = jedisUtil.getJedis();
        boolean flag = jedis.getbit(signUtils.getUserSignKey(userId,date),date.getDayOfMonth()-1);
        jedisUtil.close(jedis);
        return flag;
    }

    @Override
    public long getSignCountOneMonth(Integer userId,LocalDate date) {
        Jedis jedis = jedisUtil.getJedis();
        long count = jedis.bitcount(signUtils.getUserSignKey(userId,date));
        jedisUtil.close(jedis);
        return count;
    }

    @Override
    public long getContinuousSignCount(Integer userId, LocalDate date) {
        Jedis jedis = jedisUtil.getJedis();
        int signCount = 0;
        String type = String.format("u%d",date.getDayOfMonth());
        //取出最大长度为date.getDayOfMonth的二进制数
        List<Long> list = jedis.bitfield(signUtils.getUserSignKey(userId,date),"GET",type,"0");
        if(list!=null && list.size()>0){
            long v = list.get(0) == null?0:list.get(0);
            for(int i=0;i<date.getDayOfMonth();i++){
                if (v >> 1 << 1 == v) {
                    // 低位为0且非当天说明连续签到中断了
                    if (i > 0) break;
                } else {
                    signCount += 1;
                }
                v >>= 1;
            }
        }
        jedisUtil.close(jedis);
        return signCount;
    }

    @Override
    public LocalDate getFirstSignDate(Integer userId, LocalDate date) {
        Jedis jedis = jedisUtil.getJedis();
        long pos = jedis.bitpos(signUtils.getUserSignKey(userId,date),true);
        jedisUtil.close(jedis);
        //判断本月是否签到
        return pos<0?null:date.withDayOfMonth((int)(pos+1));
    }

    @Override
    public Map<String, Boolean> getSignInfo(Integer userId, LocalDate date) {
        Jedis jedis = jedisUtil.getJedis();
        //创建返回的map并且设置大小为天数
        Map<String,Boolean> signMap = new HashMap<>(date.lengthOfMonth());
        String type = String.format("u%d",date.lengthOfMonth());
        List<Long> list = jedis.bitfield(signUtils.getUserSignKey(userId,date),"GET",type,"0");
        if (list != null && list.size() > 0) {
            // 由低位到高位，为0表示未签，为1表示已签
            long v = list.get(0) == null ? 0 : list.get(0);
            for (int i = date.lengthOfMonth(); i > 0; i--) {
                LocalDate d = date.withDayOfMonth(i);
                signMap.put(SignUtils.formatDate(d,"yyyy-MM-dd"),v >> 1 << 1 != v);
                v >>= 1;
            }
        }
        jedisUtil.close(jedis);
        return signMap;
    }

    @Override
    public long getContinuousSignCountByTotalMonth(Integer userId, LocalDate date) {
        Jedis jedis = jedisUtil.getJedis();
        int signCount = 0;
        int max = signCount;
        String type = String.format("u%d",date.lengthOfMonth());
        //取出最大长度为date.getDayOfMonth的二进制数
        List<Long> list = jedis.bitfield(signUtils.getUserSignKey(userId,date),"GET",type,"0");
        if(list!=null && list.size()>0){
            //获取二进制数转为的十进制数
            long v = list.get(0) == null?0:list.get(0);
                for(int i=0;i<date.lengthOfMonth();i++){
                    if (v >> 1 << 1 == v) {
                        // 低位为0且非当天说明连续签到中断了
                        if (i > 0){
                            if(signCount>max){
                                max = signCount;
                                signCount = 0;
                            }
                        }
                    } else {
                        signCount += 1;
                    }
                    v >>= 1;
                }

            }
        jedisUtil.close(jedis);
        return max;
    }

    @Override
    public String doSignBQ(Integer userId, LocalDate date) {
        Jedis jedis = jedisUtil.getJedis();
        jedis.setbit(signUtils.getUserSignKey(userId,date),date.getDayOfMonth()-1,true);
        return "补签成功";
    }
}
